// progress class, added by regret

#include "burner.h"

Progress* burnerProgress = NULL;

static HWND hProgressDlg = NULL;
static HANDLE hProgressThread = NULL;
static unsigned progressThreadID = 0;
static HANDLE hEvent = NULL;

// progress class
Progress::Progress()
{
	progressMin = 0;
	progressMax = 1 << 30;

	progressPosBurn = 0;
	progressPosBurner = 0;
}

bool Progress::range(double progressRange)
{
	if (!hProgressThread || !hProgressDlg) {
		return false;
	}

	progressMin = -(int)((double)progressMax * progressRange);
	SendDlgItemMessage(hProgressDlg, IDC_WAIT_PROG, PBM_SETRANGE32, progressMin, progressMax);
	return true;
}

bool Progress::update(double progress, const char* text, bool abs)
{
	if (!hProgressThread || !hProgressDlg) {
		return false;
	}

	if (text) {
		SendDlgItemMessageA(hProgressDlg, IDC_WAIT_LABEL_B2, WM_SETTEXT, 0, (LPARAM)text);
//		SetWindowText(hScrnWnd, text);
	}

	if (abs) {
		progressPosBurn = (int)((double)(-progressMin) * progress);
		if (progressPosBurn > -progressMin) {
			progressPosBurn = -progressMin;
		}
		SendDlgItemMessage(hProgressDlg, IDC_WAIT_PROG, PBM_SETPOS, (WPARAM)(progressMin + progressPosBurn + progressPosBurner), 0);
	} else {
		if (progress) {
			progressPosBurn += (int)((double)(-progressMin) * progress);
			if (progressPosBurn > -progressMin) {
				progressPosBurn = -progressMin;
			}
			SendDlgItemMessage(hProgressDlg, IDC_WAIT_PROG, PBM_SETPOS, (WPARAM)(progressMin + progressPosBurn + progressPosBurner), 0);
		}
	}

	return true;
}

bool Progress::updateBurner(double progress, const wchar_t* text, bool abs)
{
	if (!hProgressThread || !hProgressDlg) {
		return false;
	}

	if (text) {
		SendDlgItemMessage(hProgressDlg, IDC_WAIT_LABEL_B2, WM_SETTEXT, 0, (LPARAM)text);
//		SetWindowText(hScrnWnd, text);
	}

	if (abs) {
		progressPosBurner = (int)((double)progressMax * progress);
		if (progressPosBurner > progressMax) {
			progressPosBurner = progressMax;
		}
		SendDlgItemMessage(hProgressDlg, IDC_WAIT_PROG, PBM_SETPOS, (WPARAM)(progressMin + progressPosBurn + progressPosBurner), 0);
	} else {
		if (progress) {
			if (progressPosBurner > progressMax) {
				progressPosBurner = progressMax;
			}
			progressPosBurner += (int)((double)progressMax * progress);
			SendDlgItemMessage(hProgressDlg, IDC_WAIT_PROG, PBM_SETPOS, (WPARAM)(progressMin + progressPosBurn + progressPosBurner), 0);
		}
	}

	return true;
}

// ----------------------------------------------------------------------------
// Code that runs in a seperate thread

static INT_PTR CALLBACK progressProc(HWND hDlg, UINT msg, WPARAM /*wParam*/, LPARAM /*lParam*/)
{
	if (msg == WM_INITDIALOG) {
		wchar_t szText[MAX_PATH];

		hProgressDlg = hDlg;

		// ==> load custom resource, added by regret
		HBITMAP hBitmap = (HBITMAP)LoadImage(hAppInst, L"res\\misc.bmp", IMAGE_BITMAP, 80, 60, LR_LOADFROMFILE);
		if (!hBitmap) {
			hBitmap = LoadBitmap(hAppInst, MAKEINTRESOURCE(BMP_MISC));
		}
		SendDlgItemMessage(hDlg, IDC_MISC, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);
		// <== load custom resource

		SendDlgItemMessage(hDlg, IDC_WAIT_PROG, PBM_SETRANGE32, burnerProgress->progressMin, burnerProgress->progressMax);

		swprintf(szText, localiseStringEx(IDS_PROGRESS_LOADING), BurnDrvGetTextA(DRV_NAME));
		SendDlgItemMessage(hDlg, IDC_WAIT_LABEL_B1, WM_SETTEXT, 0, (LPARAM)szText);

		ShowWindow(GetDlgItem(hDlg, IDC_WAIT_LABEL_B1), TRUE);
		ShowWindow(GetDlgItem(hDlg, IDC_WAIT_LABEL_B2), TRUE);

		wndInMid(hDlg, hScrnWnd);
		SetForegroundWindow(hDlg);
		SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);

		return TRUE;
	}

	return FALSE;
}

static unsigned __stdcall doProgress(void* param)
{
	MSG msg;
	BOOL ret;

	// Raise the thread priority for this thread
	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

	localiseCreateDialog(IDD_WAIT, NULL, (DLGPROC)progressProc);

	if (hEvent) {
		SetEvent(hEvent);
	}

	while (1) {
		ret = GetMessage(&msg, NULL, 0, 0);

		if (ret != 0 && ret != -1) {
			// See if we need to end the thread
			if (msg.message == (WM_APP + 0)) {
				break;
			}

			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	DestroyWindow(hProgressDlg);

	return 0;
}

// ----------------------------------------------------------------------------

bool progressUpdateBurner(double progress, const wchar_t* text, bool abs)
{
	if (burnerProgress) {
		return burnerProgress->updateBurner(progress, text, abs);
	}
	return false;
}

int progressCreate()
{
	if (hProgressDlg || hProgressThread) {
		return 1;
	}

	hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	burnerProgress = new Progress();
	if (!burnerProgress) {
		return 1;
	}
	burnInterface.setIProgress(burnerProgress);

	hProgressThread = (HANDLE)_beginthreadex(NULL, 0, doProgress, NULL, 0, &progressThreadID);

	WaitForSingleObject(hEvent, 5000);

	CloseHandle(hEvent);
	hEvent = NULL;

	return 0;
}

int progressDestroy()
{
	if (!hProgressThread) {
		return 0;
	}

	// Signal the prgress thread to end
	PostThreadMessage(progressThreadID, WM_APP + 0, 0, 0);

	hProgressDlg = NULL;

	CloseHandle(hProgressThread);
	hProgressThread = NULL;
	progressThreadID = 0;

	if (burnerProgress) {
		delete burnerProgress;
		burnerProgress = NULL;
	}

	return 0;
}
